home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 17
/
CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso
/
CUCD
/
Programming
/
DiceSource
/
lib
/
unix
/
select.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-09-09
|
5KB
|
271 lines
/*
* UNIX/SELECT.C
*
* (c)Copyright 1992-1997 Obvious Implementations Corp. Redistribution and
* use is allowed under the terms of the DICE-LICENSE FILE,
* DICE-LICENSE.TXT.
*/
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/ports.h>
#include <dos/dos.h>
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <lib/misc.h>
#include <lib/requestfh.h>
#include <lib/waitmsg.h>
#include <devices/timer.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#include <lists.h>
typedef struct MsgPort MsgPort;
typedef struct Message Message;
typedef struct Node Node;
typedef struct List List;
typedef struct timerequest Iot;
typedef struct ReqNode {
Node rn_Node;
short rn_Fd;
long rn_Fh;
long rn_Flags;
Message rn_Message;
} ReqNode;
#define RNF_RFDS 0x0001
#define RNF_WFDS 0x0002
#define RNF_RETURNED 0x0100
static List FreeList = { (Node *)&FreeList.lh_Tail, NULL, (Node *)&FreeList.lh_Head };
static Iot Iot0;
static MsgPort IoSink;
void QueueMessage(List *, _IOFDS *, int, long, long);
void
_select_exit()
{
if (Iot0.tr_node.io_Device) {
CloseDevice((void *)&Iot0);
Iot0.tr_node.io_Device = NULL;
}
}
int
select(setSize, rfds, wfds, xfds, tv)
int setSize;
fd_set *rfds;
fd_set *wfds;
fd_set *xfds;
struct timeval *tv;
{
List actList;
short i, j;
short sigInt = 0;
short iotIp = 0;
if (IoSink.mp_Flags == 0) {
IoSink.mp_Node.ln_Type = NT_MSGPORT;
IoSink.mp_Flags = PA_SIGNAL;
IoSink.mp_SigBit= SIGB_SINGLE;
IoSink.mp_SigTask = FindTask(NULL);
NewList(&IoSink.mp_MsgList);
Iot0.tr_node.io_Message.mn_ReplyPort = &IoSink;
Iot0.tr_node.io_Command = TR_ADDREQUEST;
OpenDevice("timer.device", UNIT_VBLANK, (void *)&Iot0, 0);
atexit(_select_exit);
}
NewList(&actList);
for (i = 0; i < setSize; i += sizeof(fd_mask) * 8) {
fd_mask mask;
_IOFDS *d;
if (rfds && (mask = rfds->fds_bits[i])) {
for (j = 0; j < sizeof(fd_mask) * 8; ++j) {
if ((mask & (1 << j)) && (d = __getfh(i + j))) {
QueueMessage(&actList, d, i + j, FREQ_RPEND, RNF_RFDS);
}
}
}
if (wfds && (mask = wfds->fds_bits[i])) {
for (j = 0; j < sizeof(fd_mask) * 8; ++j) {
if ((mask & (1 << j)) && (d = __getfh(i + j))) {
QueueMessage(&actList, d, i + j, FREQ_WAVAIL, RNF_WFDS);
}
}
}
}
/*
* nothing was queued!
*/
if (GetHead(&actList) == NULL) {
#ifdef DEBUG
puts("ACTLIST EMPTY");
#endif
errno = 0;
return(-1);
}
/*
* start timeout
*/
if (tv && (tv->tv_secs || tv->tv_micro)) {
#ifdef DEBUG
puts("START TIMEOUT");
#endif
Iot0.tr_time.tv_secs = tv->tv_secs;
Iot0.tr_time.tv_micro = tv->tv_micro;
SendIO((void *)&Iot0);
iotIp = 1;
}
/*
* wait for event(s)
*/
i = 0;
for (;;) {
{
ReqNode *rn;
while (rn = (struct ReqNode *)GetMsg(&IoSink)) {
if ((char *)rn == (char *)&Iot0) {
tv->tv_secs = 0;
tv->tv_micro = 0;
iotIp = 0;
#ifdef DEBUG
puts("TIMEOUT");
#endif
continue;
}
#ifdef DEBUG
puts("REQ RETURNED");
#endif
rn = (ReqNode *)((char *)rn - offsetof(ReqNode, rn_Message));
rn->rn_Flags |= RNF_RETURNED;
++i;
}
}
/*
* if tv was not NULL and was 0, break out
*/
if (tv && tv->tv_secs == 0 && tv->tv_micro == 0) {
#ifdef DEBUG
puts("TIME ENDED");
#endif
break;
}
if (i) {
#ifdef DEBUG
puts("DESCRIPT FOUND");
#endif
break;
}
{
long mask = Wait(SIGF_SINGLE | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D);
if (mask & (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D)) {
sigInt = 1;
break;
}
}
}
if (iotIp) {
AbortIO((void *)&Iot0);
WaitIO((void *)&Iot0);
}
/*
* abort remaining requests, clearing those that have not been returned
* (no event pending)
*/
i = 0;
{
ReqNode *rn;
while (rn = (struct ReqNode *)RemHead(&actList)) {
if (rn->rn_Message.mn_Node.ln_Type == NT_MESSAGE) {
if (rn->rn_Flags & RNF_RFDS)
FD_CLR(rn->rn_Fd, rfds);
if (rn->rn_Flags & RNF_WFDS)
FD_CLR(rn->rn_Fd, wfds);
RequestFH(rn->rn_Fh, &rn->rn_Message, FREQ_ABORT);
WaitMsg(&rn->rn_Message);
} else {
if ((rn->rn_Flags & RNF_RETURNED) == 0)
WaitMsg(&rn->rn_Message);
++i;
}
AddTail(&FreeList, &rn->rn_Node);
}
}
/*
* SIGINT?
*/
if (sigInt) {
raise(SIGINT);
if (i == 0) {
i = -1;
errno = EINTR;
}
} else if (i == 0) {
i = -1;
errno = EWOULDBLOCK;
}
return(i);
}
void
QueueMessage(list, d, fd, how, flags)
List *list;
_IOFDS *d;
int fd;
long how;
long flags;
{
ReqNode *rn;
if ((rn = (struct ReqNode *)RemHead(&FreeList)) == NULL)
rn = malloc(sizeof(ReqNode));
if (rn) {
rn->rn_Message.mn_ReplyPort = &IoSink;
rn->rn_Flags = flags;
rn->rn_Fh = d->fd_Fh;
rn->rn_Fd = fd;
if (RequestFH(d->fd_Fh, &rn->rn_Message, how)) {
#ifdef DEBUG
printf("ADDED %d\n", fd);
#endif
AddTail(list, &rn->rn_Node);
} else {
#ifdef DEBUG
printf("NOTSUPPORTED: FD %d\n", fd);
#endif
AddTail(&FreeList, &rn->rn_Node);
}
}
}